//**********************************************************************
// Purpose: Verilog module containing a synthesizable CRC function
// * polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
// * data width: 8
// Author: xychen
// Date: 2009-3-20  create file
//       2010-5-11  changed to a integreted module
//	 2010-6-18  changed logic to use with "crc32_en" is not continuous
//       2010-6-22  add "crc32_cal_end" to indicate crc32_value can be fetched
//**********************************************************************
`timescale 1ns/1ns

module crc32_d8(
	input	wire		sclk,
	input	wire		rst_n,
	
	input	wire		crc32_init,
	input	wire		crc32_en,
	
	input	wire		crc32_en_end,
	input	wire	[7:0]	data_for_crc32,
	
	output	reg		crc32_cal_end,
	output	reg	[31:0]	crc32_value
		);
//***********************************************************************
reg	[2:0]	crc32_en_cnt;
reg	[3:0]	crc32_en_end_temp;
wire		crc32_en_prolong;
reg	[7:0]	d;
wire	[31:0]	c;
//***********************************************************************
//crc32_en_cnt[2:0]
always@(posedge sclk or negedge rst_n)
	if(!rst_n)
		crc32_en_cnt <= 3'b0;
	else if(crc32_init==1)
		crc32_en_cnt <= 3'b0;
	else if(crc32_en==1)
	begin
		if(crc32_en_cnt<5)
			crc32_en_cnt <= crc32_en_cnt + 1'b1;
	end

//crc32_en_end_temp[3:0]
always@(posedge sclk or negedge rst_n)
	if(!rst_n)
		crc32_en_end_temp <= 4'b0;
	else
		crc32_en_end_temp <= {crc32_en_end_temp[2:0],crc32_en_end};

//crc32_en_prolong
assign crc32_en_prolong = crc32_en_end | crc32_en_end_temp[0] | crc32_en_end_temp[1] | crc32_en_end_temp[2];

//d[7:0]
always@*
	if(crc32_en==1)
	begin
		if(crc32_en_cnt<4)
			d = ~data_for_crc32;
		else
			d = data_for_crc32;
	end
	else
		d = 8'b0;

//c[31:0]
assign c = crc32_value;

//crc32_value[31:0]
always@(posedge sclk or negedge rst_n)
	if(!rst_n)
		crc32_value <= 32'h00000000;
	else if(crc32_init==1)
		crc32_value <= 32'h00000000;
	else if(crc32_en==1 | crc32_en_prolong==1)
	begin
		crc32_value[31] <= c[29]^c[23];
		crc32_value[30] <= c[31]^c[28]^c[22];
		crc32_value[29] <= c[31]^c[30]^c[27]^c[21];
		crc32_value[28] <= c[30]^c[29]^c[26]^c[20];
		crc32_value[27] <= c[31]^c[29]^c[28]^c[25]^c[19];
		crc32_value[26] <= c[30]^c[28]^c[27]^c[24]^c[18];
		crc32_value[25] <= c[27]^c[26]^c[17];
		crc32_value[24] <= c[31]^c[26]^c[25]^c[16];
		crc32_value[23] <= c[30]^c[25]^c[24]^c[15];
		crc32_value[22] <= c[24]^c[14];
		crc32_value[21] <= c[29]^c[13];
		crc32_value[20] <= c[28]^c[12];
		crc32_value[19] <= c[31]^c[27]^c[11];
		crc32_value[18] <= c[31]^c[30]^c[26]^c[10];
		crc32_value[17] <= c[30]^c[29]^c[25]^c[9];
		crc32_value[16] <= c[29]^c[28]^c[24]^c[8];
		crc32_value[15] <= c[31]^c[29]^c[28]^c[27]^c[7];
		crc32_value[14] <= c[31]^c[30]^c[28]^c[27]^c[26]^c[6];
		crc32_value[13] <= c[31]^c[30]^c[29]^c[27]^c[26]^c[25]^c[5];
		crc32_value[12] <= c[30]^c[29]^c[28]^c[26]^c[25]^c[24]^c[4];
		crc32_value[11] <= c[28]^c[27]^c[25]^c[24]^c[3];
		crc32_value[10] <= c[29]^c[27]^c[26]^c[24]^c[2];
		crc32_value[9]  <= c[29]^c[28]^c[26]^c[25]^c[1];
		crc32_value[8]  <= c[28]^c[27]^c[25]^c[24]^c[0];
		
		crc32_value[7]  <= c[31]^c[29]^c[27]^c[26]^c[24]^d[0];
		crc32_value[6]  <= c[31]^c[30]^c[29]^c[28]^c[26]^c[25]^d[1];
		crc32_value[5]  <= c[31]^c[30]^c[29]^c[28]^c[27]^c[25]^c[24]^d[2];
		crc32_value[4]  <= c[30]^c[28]^c[27]^c[26]^c[24]^d[3];
		crc32_value[3]  <= c[31]^c[27]^c[26]^c[25]^d[4];
		crc32_value[2]  <= c[31]^c[30]^c[26]^c[25]^c[24]^d[5];
		crc32_value[1]  <= c[31]^c[30]^c[25]^c[24]^d[6];
		crc32_value[0]  <= c[30]^c[24]^d[7];
	end
	else if(crc32_en_end_temp[3]==1)
		crc32_value <= ~{crc32_value[24],crc32_value[25],crc32_value[26],crc32_value[27],crc32_value[28],crc32_value[29],crc32_value[30],crc32_value[31],
				 crc32_value[16],crc32_value[17],crc32_value[18],crc32_value[19],crc32_value[20],crc32_value[21],crc32_value[22],crc32_value[23],
				 crc32_value[8], crc32_value[9], crc32_value[10],crc32_value[11],crc32_value[12],crc32_value[13],crc32_value[14],crc32_value[15],
				 crc32_value[0], crc32_value[1], crc32_value[2], crc32_value[3], crc32_value[4], crc32_value[5], crc32_value[6], crc32_value[7]};

//crc32_cal_end
always@(posedge sclk or negedge rst_n)
	if(!rst_n)
		crc32_cal_end <= 1'b0;
	else if(crc32_en_end_temp[3]==1)
		crc32_cal_end <= 1'b1;
	else
		crc32_cal_end <= 1'b0;
//***********************************************************************
endmodule